1 /*
2 * Scope: a generic MVC framework.
3 * Copyright (c) 2000-2002, The Scope team
4 * All rights reserved.
5 *
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 *
18 * Neither the name "Scope" nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
27 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 *
36 * $Id: ListModel.java,v 1.12 2002/09/12 10:51:03 ludovicc Exp $
37 */
38 package org.scopemvc.model.collection;
39
40
41 import java.util.ArrayList;
42 import java.util.Collection;
43 import java.util.Iterator;
44 import java.util.List;
45 import java.util.ListIterator;
46 import org.apache.commons.logging.Log;
47 import org.apache.commons.logging.LogFactory;
48 import org.scopemvc.core.ModelChangeEvent;
49 import org.scopemvc.core.ModelChangeEventSource;
50 import org.scopemvc.core.Selector;
51 import org.scopemvc.model.basic.BasicModel;
52
53 /***
54 * <P>
55 *
56 * A BasicModel wrapper for an <CODE>List</CODE> that can propagate changes to
57 * contained Models up the Model hierarchy. The list itself is exposed via the
58 * "list" property, however, changes to this list must be made through this
59 * class's public API in order to maintain the event propagation. </P> <P>
60 *
61 * By default ListModel registers itself as a listener to Models that are added
62 * to the list and deregisters when those Models are removed. This behaviour can
63 * be changed at creation so that ModelChangeEvent propagation is disabled. </P>
64 *
65 * @author <A HREF="mailto:haruki_zaemon@users.sourceforge.net">Simon Harris</A>
66 * @author <A HREF="mailto:smeyfroi@users.sourceforge.net">Steve Meyfroidt</A>
67 * @created 05 September 2002
68 * @version $Revision: 1.12 $
69 */
70 public class ListModel extends BasicModel implements List {
71
72 /***
73 * TODO: describe of the Field
74 */
75 public static final Selector LIST = Selector.fromString("list");
76
77 // ----------------- for debug -----------------------
78
79 /***
80 * TODO: describe of the Field
81 */
82 protected static final String TO_STRING_SEPARATOR = ", ";
83 /***
84 * TODO: describe of the Field
85 */
86 protected static final int TO_STRING_SEPARATOR_LENGTH = TO_STRING_SEPARATOR.length();
87
88 private static final Log LOG = LogFactory.getLog(ListModel.class);
89
90 /***
91 * TODO: describe of the Field
92 */
93 protected List contents;
94
95 /***
96 * TODO: describe of the Field
97 */
98 protected boolean propagateModelChanges;
99
100
101 /***
102 * Constructor for the ListModel object
103 */
104 public ListModel() {
105 this(true, new ArrayList(10));
106 }
107
108
109 /***
110 * Constructor for the ListModel object
111 *
112 * @param inList TODO: Describe the Parameter
113 */
114 public ListModel(List inList) {
115 this(true, inList);
116 }
117
118
119 /***
120 * Constructor for the ListModel object
121 *
122 * @param inPropagateModelChanges TODO: Describe the Parameter
123 */
124 public ListModel(boolean inPropagateModelChanges) {
125 propagateModelChanges = inPropagateModelChanges;
126 }
127
128
129 /***
130 * Constructor for the ListModel object
131 *
132 * @param inPropagateModelChanges TODO: Describe the Parameter
133 * @param inList TODO: Describe the Parameter
134 */
135 public ListModel(boolean inPropagateModelChanges, List inList) {
136 this(inPropagateModelChanges);
137 setList(inList);
138 }
139
140
141 /***
142 * Gets the list
143 *
144 * @return The list value
145 */
146 public List getList() {
147 return contents;
148 }
149
150
151 /***
152 * Gets the size
153 *
154 * @return The size value
155 */
156 public int getSize() {
157 if (contents == null) {
158 return 0;
159 }
160 return contents.size();
161 }
162
163
164 /***
165 * Gets the index of
166 *
167 * @param inValue TODO: Describe the Parameter
168 * @return The indexOf value
169 */
170 public int getIndexOf(Object inValue) {
171 if (inValue == null) {
172 return -1;
173 }
174 return contents.indexOf(inValue);
175 }
176
177
178 /***
179 * Gets the empty
180 *
181 * @return The empty value
182 */
183 public boolean isEmpty() {
184 return getList().isEmpty();
185 }
186
187
188 /***
189 * TODO: document the method
190 *
191 * @param index TODO: Describe the Parameter
192 * @return TODO: Describe the Return Value
193 */
194 public Object get(int index) {
195 return contents.get(index);
196 }
197
198
199 /***
200 * Set contents to the passed Object list and fire a ModelChangeEvent.
201 *
202 * @param inContents The new list value
203 */
204 public void setList(List inContents) {
205
206 if (propagateModelChanges) {
207 // Clear up old list if it contained any Models
208 if (contents != null) {
209 for (Iterator i = contents.iterator(); i.hasNext(); ) {
210 Object o = i.next();
211 if (o instanceof ModelChangeEventSource) {
212 ((ModelChangeEventSource) o).removeModelChangeListener(this);
213 }
214 }
215 }
216 }
217
218 contents = inContents;
219
220 if (propagateModelChanges) {
221 // Register as listener to any Models in the new list
222 if (contents != null) {
223 for (Iterator i = contents.iterator(); i.hasNext(); ) {
224 Object o = i.next();
225 if (o instanceof ModelChangeEventSource) {
226 ((ModelChangeEventSource) o).addModelChangeListener(this);
227 }
228 }
229 }
230 }
231
232 fireModelChange(ModelChangeEvent.VALUE_CHANGED, LIST);
233 }
234
235
236 /***
237 * TODO: document the method
238 *
239 * @param index TODO: Describe the Parameter
240 * @param element TODO: Describe the Parameter
241 * @return TODO: Describe the Return Value
242 */
243 public Object set(int index, Object element) {
244 if (LOG.isDebugEnabled()) {
245 LOG.debug("set: " + index + ", " + element);
246 }
247
248 Object oldValue = contents.get(index);
249 contents.set(index, element);
250 fireModelChange(VALUE_CHANGED, Selector.fromInt(index));
251
252 if (propagateModelChanges) {
253 if (oldValue instanceof ModelChangeEventSource) {
254 ((ModelChangeEventSource) oldValue).removeModelChangeListener(this);
255 }
256 if (element instanceof ModelChangeEventSource) {
257 ((ModelChangeEventSource) element).addModelChangeListener(this);
258 }
259 }
260
261 return oldValue;
262 }
263
264 /***
265 * TODO: document the method
266 *
267 * @return TODO: Describe the Return Value
268 */
269 public String toString() {
270
271 if (contents == null) {
272 return "";
273 }
274
275 StringBuffer result = new StringBuffer("(");
276
277 for (Iterator i = contents.iterator(); i.hasNext(); ) {
278 Object o = i.next();
279 result.append(o == null ? "<null>" : o.toString());
280 result.append(TO_STRING_SEPARATOR);
281 }
282
283 if (contents.size() > 0) {
284 result.setLength(result.length() - TO_STRING_SEPARATOR_LENGTH);
285 }
286 result.append(')');
287
288 return result.toString();
289 }
290
291
292 // -------------------------- implement List ------------------------------
293
294 /***
295 * TODO: document the method
296 *
297 * @return TODO: Describe the Return Value
298 */
299 public Iterator iterator() {
300 return getList().iterator();
301 }
302
303
304 /***
305 * TODO: document the method
306 *
307 * @return TODO: Describe the Return Value
308 */
309 public int size() {
310 return getList().size();
311 }
312
313
314 /***
315 * TODO: document the method
316 *
317 * @param a TODO: Describe the Parameter
318 * @return TODO: Describe the Return Value
319 */
320 public Object[] toArray(Object a[]) {
321 return getList().toArray(a);
322 }
323
324
325 /***
326 * TODO: document the method
327 *
328 * @param o TODO: Describe the Parameter
329 * @return TODO: Describe the Return Value
330 */
331 public boolean contains(Object o) {
332 return getList().contains(o);
333 }
334
335
336 /***
337 * TODO: document the method
338 *
339 * @param o TODO: Describe the Parameter
340 * @return TODO: Describe the Return Value
341 */
342 public boolean remove(Object o) {
343 int i = indexOf(o);
344 if (i < 0) {
345 return false;
346 }
347 remove(i);
348 return true;
349 }
350
351
352 /***
353 * TODO: document the method
354 *
355 * @return TODO: Describe the Return Value
356 */
357 public Object[] toArray() {
358 return getList().toArray();
359 }
360
361
362 /***
363 * Adds an element to the All attribute of the ListModel object
364 *
365 * @param c The element to be added to the All attribute
366 * @return TODO: Describe the Return Value
367 */
368 public boolean addAll(Collection c) {
369 boolean result = false;
370 makeActive(false);
371 try {
372 for (Iterator i = c.iterator(); i.hasNext(); ) {
373 result = result | add(i.next());
374 }
375 } finally {
376 makeActive(true);
377 }
378 fireModelChange(VALUE_CHANGED, null);
379 return result;
380 }
381
382
383 /***
384 * TODO: document the method
385 *
386 * @param o TODO: Describe the Parameter
387 * @return TODO: Describe the Return Value
388 */
389 public boolean add(Object o) {
390 if (LOG.isDebugEnabled()) {
391 LOG.debug("add: " + o);
392 }
393 if (!contents.add(o)) {
394 return false;
395 }
396
397 if (propagateModelChanges && o instanceof ModelChangeEventSource) {
398 ((ModelChangeEventSource) o).addModelChangeListener(this);
399 }
400 fireModelChange(VALUE_ADDED, Selector.fromInt(contents.size() - 1));
401 return true;
402 }
403
404
405 /***
406 * TODO: document the method
407 *
408 * @param c TODO: Describe the Parameter
409 * @return TODO: Describe the Return Value
410 */
411 public boolean removeAll(Collection c) {
412 boolean result = false;
413 makeActive(false);
414 try {
415 for (Iterator i = c.iterator(); i.hasNext(); ) {
416 result = result | remove(i.next());
417 }
418 } finally {
419 makeActive(true);
420 }
421 fireModelChange(VALUE_CHANGED, null);
422 return result;
423 }
424
425
426 /***
427 * TODO: document the method
428 *
429 * @param c TODO: Describe the Parameter
430 * @return TODO: Describe the Return Value
431 */
432 public boolean containsAll(Collection c) {
433 return getList().containsAll(c);
434 }
435
436
437 /***
438 * TODO: document the method
439 */
440 public void clear() {
441 makeActive(false);
442 try {
443 if (propagateModelChanges) {
444 for (Iterator i = contents.iterator(); i.hasNext(); ) {
445 Object o = i.next();
446 if (o instanceof ModelChangeEventSource) {
447 ((ModelChangeEventSource) o).removeModelChangeListener(this);
448 }
449 }
450 }
451 contents.clear();
452 } finally {
453 makeActive(true);
454 }
455 fireModelChange(VALUE_CHANGED, null);
456 }
457
458
459 /***
460 * Adds an element to the All attribute of the ListModel object
461 *
462 * @param index The element to be added to the All attribute
463 * @param c The element to be added to the All attribute
464 * @return TODO: Describe the Return Value
465 */
466 public boolean addAll(int index, Collection c) {
467 boolean result = false;
468 makeActive(false);
469 try {
470 for (Iterator i = c.iterator(); i.hasNext(); ) {
471 result = result | add(i.next());
472 }
473 } finally {
474 makeActive(true);
475 }
476 fireModelChange(VALUE_CHANGED, null);
477 return result;
478 }
479
480
481 /***
482 * TODO: document the method
483 *
484 * @return TODO: Describe the Return Value
485 */
486 public int hashCode() {
487 return getList().hashCode();
488 }
489
490
491 /***
492 * TODO: document the method
493 *
494 * @param c TODO: Describe the Parameter
495 * @return TODO: Describe the Return Value
496 */
497 public boolean retainAll(Collection c) {
498 List original = new ArrayList(contents);
499 boolean result = false;
500 makeActive(false);
501 try {
502 for (Iterator i = original.iterator(); i.hasNext(); ) {
503 Object o = i.next();
504 if (!c.contains(o)) {
505 remove(o);
506 result = true;
507 }
508 }
509 } finally {
510 makeActive(true);
511 }
512 fireModelChange(VALUE_CHANGED, null);
513 return result;
514 }
515
516
517 /***
518 * TODO: document the method
519 *
520 * @param o TODO: Describe the Parameter
521 * @return TODO: Describe the Return Value
522 */
523 public boolean equals(Object o) {
524 return getList().equals(o);
525 }
526
527
528 /***
529 * TODO: document the method
530 *
531 * @param index TODO: Describe the Parameter
532 * @return TODO: Describe the Return Value
533 */
534 public Object remove(int index) {
535 if (contents == null) {
536 return null;
537 }
538
539 Object oldValue = contents.remove(index);
540 if (propagateModelChanges && oldValue instanceof ModelChangeEventSource) {
541 ((ModelChangeEventSource) oldValue).removeModelChangeListener(this);
542 }
543 if (oldValue != null) {
544 fireModelChange(VALUE_REMOVED, Selector.fromInt(index));
545 }
546 return oldValue;
547 }
548
549
550 /***
551 * TODO: document the method
552 *
553 * @param o TODO: Describe the Parameter
554 * @return TODO: Describe the Return Value
555 */
556 public int lastIndexOf(Object o) {
557 return getList().lastIndexOf(o);
558 }
559
560
561 /***
562 * TODO: document the method
563 *
564 * @param index TODO: Describe the Parameter
565 * @param o TODO: Describe the Parameter
566 */
567 public void add(int index, Object o) {
568 getList().add(index, o);
569 if (propagateModelChanges && o instanceof ModelChangeEventSource) {
570 ((ModelChangeEventSource) o).addModelChangeListener(this);
571 }
572 fireModelChange(VALUE_ADDED, Selector.fromInt(index));
573 }
574
575
576 /***
577 * TODO: document the method
578 *
579 * @param index TODO: Describe the Parameter
580 * @return TODO: Describe the Return Value
581 */
582 public ListIterator listIterator(int index) {
583 return getList().listIterator(index);
584 }
585
586
587 /***
588 * TODO: document the method
589 *
590 * @param o TODO: Describe the Parameter
591 * @return TODO: Describe the Return Value
592 */
593 public int indexOf(Object o) {
594 return getList().indexOf(o);
595 }
596
597
598 /***
599 * TODO: document the method
600 *
601 * @return TODO: Describe the Return Value
602 */
603 public ListIterator listIterator() {
604 return getList().listIterator();
605 }
606
607
608 /***
609 * TODO: document the method
610 *
611 * @param fromIndex TODO: Describe the Parameter
612 * @param toIndex TODO: Describe the Parameter
613 * @return TODO: Describe the Return Value
614 */
615 public List subList(int fromIndex, int toIndex) {
616 return getList().subList(fromIndex, toIndex);
617 }
618 }
This page was automatically generated by Maven